株式会社インデペンデンスシステムズ横浜

システム開発エンジニアの西田五郎が運営しております。Raspberry Pi や Arduino その他新規開発案件のご依頼をお待ちしております。

Node.js Raspberry Pi

Raspberry PiでのNode.jsの導入(その2)Webサーバ的なプログラム

投稿日:2015年2月28日 更新日:

Raspberry PiでのNode.jsの導入の2回目です。前回はインストールと動作確認でした。今回はもう少しWebサーバ的なプログラムを作成してみます。今現在で日本のNode.jsの公式ページにもリンクがある以下のページを見ながら作成しました。合わせて参照して頂ければと思います。このページは私のようにサーバサイドのJava、PHP等の経験はあるけどサーバサイドのJavaScriptは初めてという方々にはいいかもしれないです。
Nodeビギナーズブック

ここでは上記サイトのプログラムとほぼ同じですが、もう少し簡単に、HTTPでカレントディレクトリの静的ファイルを送信する機能と、特定のURLでは何かの処理を実行するための機能があります。特にRaspberry Pi独自のGPIO等を使っていないのでパソコン等での他のLinuxディストリビューションでも動作すると思います。

ここでの処理は、たとえば、HTMLファイル、cssファイル、画像ファイルがカレントディレクトリに存在する状態で、ブラウザから以下のように表示出来ます。URLは、Raspberry PiでAvahi を使ってホスト名でアクセスするで書いたAvahiを使って、サーバ名.localでアクセスしています。もちろん、IPアドレスでもアクセス出来ました。
0001

特定のURLで以下のように表示だけですが処理出来ます。
0007

ファイルがない場合は以下のように返します。
0009

このように、Webサーバー的な機能がありますが、リクエストをマルチで処理する機能はありません。そのあたりは、Nodeビギナーズブックにブロッキングとノンブロッキングの項目から説明があります。ここではHTTP的な通信が出来ればということにしました。Node.jsでindex.jsから起動出来ます。

ここからプログラムの説明です。JavaScriptの特徴である、関数渡し(匿名関数、匿名関数)、イベント駆動コールバック等を使っていますが、このあたりの説明は省略します。必要な場合は、Nodeビギナーズブック等を参照して下さい。また私も今回初めてNode.jsを使っています。ご了承頂ければと思います。

以下のファイルを作成しました。(Nodeビギナーズブックとほぼ同じですがファイルを返す処理を追加しました。)

index.js – サーバ、ルータ、リクエストハンドラを構成してサーバを起動する。
server.js – 指定されたルータ、リクエストハンドラでHTTPサーバを起動する。
router.js – リクエストのURLからのルーティングの処理を行う。
requestHandlers.js – リクエストごとの各処理の実装。

ファイル一式は以下からダウンロード出来ます。(※単純なテスト的なプログラムです。不具合等は弊社では一切の責任を負いかねます。)
今回のスクリプトとテストファイル一式

index.jsは最後にして、server.jsから書きます。server.jsは以下です。HTTPサーバです。リクエストを受け取るとルーティングへ渡します。

var http = require("http");
var url = require("url");

function start(route, handle) {
	function onRequest(request, response) {
    		var pathname = url.parse(request.url).pathname;
    		console.log("Request for " + pathname + " received.");

		route(handle, pathname, response, request);
  	}

	http.createServer(onRequest).listen(8888);
	console.log("Server has started.");
}
exports.start = start;

router.jsは以下です。ルーティングの処理です。実際はルーティングの処理というほどでもないですが、特定の機能のURLであればその処理(ハンドラ)を設定して、それ以外は静的ファイルが指定されていればそのファイルを読み込んでハンドラへ渡します。それ以外はそれらしいHTTPステータスのハンドラへ渡します。

var fs = require("fs")

function route(handle, pathname, response, request) {
	console.log("About to route a request for " + pathname);

	if (typeof handle[pathname] === 'function') {
		handle[pathname](response, request);
	} 
	else 
	{
		pathname = "." + pathname;

		fs.exists(pathname, function(exists){
        		console.log(pathname+" "+exists);
        		
			if (!exists) { 
				handle["http404"](response); 
				return; 
			}
        		fs.readFile(pathname, "binary", function(err, file){
                		if (err) { 
					handle["http500"](err); 
					return ; 
				}
                		handle["http200"](file, response);  
        		});
		});
  	}
}
exports.route = route;

requestHandlers.js は以下です。start()がデフォルトの処理で、action1()、action2()が特定の処理を想定していて、http200()からがhttpの処理的なハンドラです。http200()でファイルを返しています。

var querystring = require("querystring")
var fs = require("fs")

var header = {
"Pragma": "no-cache",
"Cache-Control" : "no-cache"
}

function start(response) {
	console.log("Request handler 'start' was called.");

	response.writeHead(200, header);
	response.end("start\n")
}

function action1(response, request) {
	console.log("Request handler 'action1' was called.");

	response.writeHead(200, header);
	response.end("action1\n")
}

function action2(response) {
  	console.log("Request handler 'action2' was called.");

	response.writeHead(200, header);
	response.end("action2\n")
}

function http200(file,response){
	console.log("Request handler '200' was called.");

	response.writeHead(200, header);
	response.write(file, "binary");
	response.end();
}

function http404(response){
	console.log("Request handler '404' was called.");

	response.writeHead(404, header);
	response.end("http404");
}

function http500(response){
	console.log("Request handler '500' was called.");

	response.writeHead(500, header);
	response.end("http500");
}

exports.start = start;
exports.action1 = action1;
exports.action2 = action2;

exports.http200 = http200;
exports.http404 = http404;
exports.http500 = http500;

最後にindex.jsです。このindex.jsから、Node index.jsとして起動します。上記のサーバ、ルータ、リクエストハンドラを構成してサーバを起動します。

var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");

var handle = {};
handle["/"] = requestHandlers.start;
handle["/action1"] = requestHandlers.action1;
handle["/action2"] = requestHandlers.action2;

handle["http200"] = requestHandlers.http200;
handle["http404"] = requestHandlers.http404;
handle["http500"] = requestHandlers.http500;

server.start(router.route, handle);

プログラムは以上です。実際には特定の処理としている action1()、action2()では何もしていなので、テスト的なプログラムになっています。それでもファイルを返す場合と分岐出来たので最初としてはいいかと思っています。またマルチでのリクエスト処理も課題です。

但しですが、Node.jsの場合はWebアプリケーションを作成する場合は、Expressに代表されるフレームワークを使うのが一般的かとは思います。今回はここまでですが、またいろいろと書きたいと思います。


AdSense

AdSense

-Node.js, Raspberry Pi

執筆者:

関連記事

Raspberry Pi Imager でSDカード書き込み時にWifiやSSH接続を設定する方法

Raspberry Pi Imager のV1.6からは、Raspberry Pi ImagerのOSや書き込み先を選択する画面からオプションでWifiやSSH接続が設定出来るようになっていました。 …

レーザーカッターでセンサーのケースを作ってみた

前回のセンサー(温湿度センサーBME280)のケースをレーザーカッターで作ってみました。もちろん3Dプリンターで作る方法もあると思いますが単純なボックス型ならレーザーカッターの方が加工時間が短いと思っ …

Raspberry Piをモニターとキーボードなしで導入する(2021年5月版 その1)全体概要からSDカードの作成まで

今現在(2021年5月)の方法でRaspberry Piをモニターとキーボードなしで導入してみます。このモニターとキーボードなしの状態はヘッドレスという表現もあるようですのでここからはこの状態をヘッド …

Remote.itを利用してRaspberry Piを公開する

remote.itを利用してRaspberry Piをインターネットに公開する方法についてです。 公開するとは文字通り何かのサービスを実装したサーバーとして利用するとか、リモートでメンテナンスするとか …

Raspberry Piをモニターとキーボードなしで導入する(2021年5月版 その3)リモートデスクトップの導入から初期設定まで

今現在(2021年5月)の方法でRaspberry Piをヘッドレス(モニターとキーボードなしの状態)で導入する方法について書いています。前回まででSSH経由でログインするところまで書きました。今回で …